package com.oneraku.service.filter;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.oneraku.service.domain.UserAdmin;
import com.oneraku.service.domain.UserInfo;
import com.oneraku.service.exceptions.InfoException;
import com.oneraku.service.exceptions.MissParameterException;
import com.oneraku.service.exceptions.UnLoginException;
import com.oneraku.service.service.IUserAdminService;
import com.oneraku.service.service.IUserInfoService;
import com.oneraku.service.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: hui.ren@huberbuy.com
 * @Date: 2020/1/10 16:34
 */
@Slf4j
public class LogFilter implements Filter {
    private final String AUTH_HEADER_KEY = "x-oneraku-token";
    private final String AUTH_PLATFORM = "x-oneraku-platform";
    private IUserInfoService userInfoService;
    private IUserAdminService userAdminService;
    private final List<String> NO_NEED_LOGIN = Arrays.asList(new String[]{
            "/user/login",
            "/user/register",
            "/user/loginAdmin",
            "/home/hotMerchant",
            "/home/v2/hotMerchant",
            "/aliyun/sts",
            "/console/login",
    });
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
        userInfoService =  ctx.getBean(IUserInfoService.class);
        userAdminService =  ctx.getBean(IUserAdminService.class);
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        String method= request.getMethod();
        if (method.equals("OPTIONS")){
            response.setStatus(200);
        } else {
            try{
                String uri = request.getRequestURI();
                RequestBeanUtils.add(new RequestBean(request));
                RequestIpUtils.add(getIpAddress(request));
                if(NO_NEED_LOGIN.contains(uri)){
                    filterChain.doFilter(request,response);
                } else {
                    checkToken(request);
                    filterChain.doFilter(request,response);
                }
            }catch (Exception e){
                RequestBean requestBean = RequestBeanUtils.get();
                requestBean.setDuration(0L);
                requestBean.setException(e);
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=utf-8");
                PrintWriter writer = response.getWriter();
                log.info("-->"+ JSONObject.toJSONString(requestBean));
                String result = "";
                if(e instanceof HttpRequestMethodNotSupportedException){
                    result  = JSONObject.toJSONString(R.failed(ResultCode.METHOD_NOT_ALLOWED));
                } else if(e instanceof HttpMessageNotReadableException){
                    result = JSONObject.toJSONString(R.failed(ResultCode.BAD_REQUEST));
                } else if(e instanceof MissParameterException){
                    result = JSONObject.toJSONString(((MissParameterException)e).getResult());
                } else if(e instanceof InfoException){
                    result = JSONObject.toJSONString(((InfoException)e).getResult(e.getMessage()));
                } else if(e instanceof UnLoginException){
                    result = JSONObject.toJSONString(((UnLoginException)e).getResult());
                 }else {
                    result = JSONObject.toJSONString(R.failed(ResultCode.SYSTEM_ERR));
                }
                writer.write(result);
            } finally {
                RequestBeanUtils.remove();
                RequestUserUtils.remove();
                RequestIpUtils.remove();
                RequestConsoleUserUtils.remove();
            }
        }
    }
    private void checkToken(HttpServletRequest request){
       String token = getToken(request);
        if(StringUtils.isEmpty(token)){
            throw new UnLoginException();
        }
        String platform = getPlatform(request);
        if(!StringUtils.isEmpty(platform) && "platform".equals(platform)){
            // 控制台
            UserAdmin userAdmin = userAdminService.getOne(Wrappers.<UserAdmin>lambdaQuery().eq(UserAdmin::getToken,token),false);
            if(null == userAdmin){
                throw new UnLoginException();
            }
            ConsoleBean consoleBean = new ConsoleBean();
            consoleBean.setId(userAdmin.getId());
            consoleBean.setIp(getIpAddress(request));
            consoleBean.setManager(userAdmin.getManager());
            consoleBean.setUsername(userAdmin.getUsername());
            consoleBean.setName(userAdmin.getName());
            RequestConsoleUserUtils.add(consoleBean);
        } else {
            // 前端
            UserInfo userInfo = userInfoService.getOne(Wrappers.<UserInfo>lambdaQuery().select(
                    UserInfo::getId,
                    UserInfo::getMobile,
                    UserInfo::getMail,
                    UserInfo::getUsername,
                    UserInfo::getTokenExpire).eq(UserInfo::getToken,token));
            if(null == userInfo){
                throw new InfoException("用户令牌不合法！");
            }
            if(userInfo.getTokenExpire() < System.currentTimeMillis()){
                throw new UnLoginException();
            }
            AuthBean authBean = new AuthBean();
            authBean.setId(userInfo.getId());
            authBean.setName(userInfo.getName());
            authBean.setUsername(userInfo.getUsername());
            authBean.setToken(userInfo.getToken());
            authBean.setMail(userInfo.getMail());
            authBean.setMobile(userInfo.getMobile());
            RequestUserUtils.add(authBean);
            userInfoService.update(null,Wrappers.<UserInfo>lambdaUpdate().set(UserInfo::getTokenExpire,System.currentTimeMillis()+Const.expire).eq(UserInfo::getId,userInfo.getId()));
        }
    }
    private String getToken(HttpServletRequest request){
        String method = request.getMethod();
        String token = request.getHeader(AUTH_HEADER_KEY);
        if(StringUtils.isEmpty(token)){
            if("GET".equals(method)){
                String[] authParam = request.getParameterValues("auth");
                if(null !=authParam && authParam.length > 0){
                    return authParam[0];
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return token;
        }
    }
    private String getPlatform(HttpServletRequest request){
        return request.getHeader(AUTH_PLATFORM);
    }
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
